﻿#define _CRT_SECURE_NO_WARNINGS 1

using namespace std;
#include <iostream>
#include <functional>

//double Divide(int a, int b)
//{
//	// 当b == 0时抛出异常
//	if (b == 0)
//	{
//		throw "Divide by zero condition!";
//	}
//	else
//	{
//		return (double)a / (double)b;
//	}
//}
//
//void Func()
//{
//	// 这⾥可以看到如果发⽣除0错误抛出异常，另外下⾯的array和array2没有得到释放。
//	// 所以这⾥捕获异常后并不处理异常，异常还是交给外⾯处理，这⾥捕获了再重新抛出去。
//	// 但是如果array2new的时候抛异常呢，就还需要套⼀层捕获释放逻辑，这⾥更好解决⽅案
//	// 是智能指针，否则代码会极其臃肿
//	int* array1 = new int[10];
//	int* array2 = new int[10]; // 抛异常呢
//	try
//	{
//		int len, time;
//		cin >> len >> time;
//		cout << Divide(len, time) << endl;
//	}
//	catch (...)
//	{
//		cout << "delete []" << array1 << endl;
//		cout << "delete []" << array2 << endl;
//		delete[] array1;
//		delete[] array2;
//		throw; // 异常重新抛出，捕获到什么抛出什么
//	}
//	// ...
//	cout << "delete []" << array1 << endl;
//	delete[] array1;
//	cout << "delete []" << array2 << endl;
//	delete[] array2;
//}
//
//int main()
//{
//	try
//	{
//		Func();
//	}
//	catch (const char* errmsg)
//	{
//		cout << errmsg << endl;
//	}
//	catch (const exception& e)
//	{
//		cout << e.what() << endl;
//	}
//	catch (...)
//	{
//		cout << "未知异常" << endl;
//	}
//	return 0;
//}


struct Date
{
	int _year;
	int _month;
	int _day;
	Date(int year = 1, int month = 1, int day = 1)
		:_year(year)
		, _month(month)
		, _day(day)
	{
	}
	~Date()
	{
		cout << "~Date()" << endl;
	}
};
//
//int main()
//{
//	auto_ptr<Date> ap1(new Date);
//	// 拷⻉时，管理权限转移，被拷⻉对象ap1悬空
//	auto_ptr<Date> ap2(ap1);
//	// 空指针访问，ap1对象已经悬空
//	//ap1->_year++;
//
//	unique_ptr<Date> up1(new Date);
//	// 不⽀持拷⻉
//	//unique_ptr<Date> up2(up1);
//	// ⽀持移动，但是移动后up1也悬空，所以使⽤移动要谨慎
//	unique_ptr<Date> up3(move(up1));
//
//	shared_ptr<Date> sp1(new Date);
//	// ⽀持拷⻉
//	shared_ptr<Date> sp2(sp1);
//	shared_ptr<Date> sp3(sp2);
//	cout << sp1.use_count() << endl;
//	sp1->_year++;
//	cout << sp1->_year << endl;
//	cout << sp2->_year << endl;
//	cout << sp3->_year << endl;
//	// ⽀持移动，但是移动后sp1也悬空，所以使⽤移动要谨慎
//	shared_ptr<Date> sp4(move(sp1));
//	return 0;
//}


namespace wusaqi
{
	template<class T>
	class auto_ptr
	{
	public:
		auto_ptr(T* ptr)
			:_ptr(ptr)
		{
		}

		auto_ptr(auto_ptr<T>& sp)
			:_ptr(sp._ptr)
		{
			// 管理权转移
			sp._ptr = nullptr;
		}

		auto_ptr<T>& operator=(auto_ptr<T>& ap)
		{
			//检测是否为⾃⼰给⾃⼰赋值
			if (this != &ap)
			{
				// 释放当前对象中资源
				if (_ptr)
					delete _ptr;
				// 转移ap中资源到当前对象中
				_ptr = ap._ptr;
				ap._ptr = NULL;
			}
			return *this;
		}

		~auto_ptr()
		{
			if (_ptr)
			{
				cout << "delete:" << _ptr << endl;
				delete _ptr;
			}
		}

		// 像指针⼀样使⽤
		T& operator*()
		{
			return *_ptr;
		}
		T* operator->()
		{
			return _ptr;
		}
	private:
		T* _ptr;
	};

	template<class T>
	class unique_ptr
	{
	public:
		explicit unique_ptr(T* ptr)
			:_ptr(ptr)
		{
		}

		~unique_ptr()
		{
			if (_ptr)
			{
				cout << "delete:" << _ptr << endl;
				delete _ptr;
			}
		}

		// 像指针⼀样使⽤
		T& operator*()
		{
			return *_ptr;
		}
		T* operator->()
		{
			return _ptr;
		}

		//禁用拷贝构造、拷贝赋值
		unique_ptr(const unique_ptr<T>& sp) = delete;
		unique_ptr<T>& operator=(const unique_ptr<T>& sp) = delete;

		//支持移动构造、移动赋值
		unique_ptr(unique_ptr<T>&& sp)
			:_ptr(sp._ptr)
		{
			sp._ptr = nullptr;
		}

		unique_ptr<T>& operator=(unique_ptr<T>&& sp)
		{
			delete _ptr;
			_ptr = sp._ptr;
			sp._ptr = nullptr;
		}

	private:
		T* _ptr;
	};
}

//template<class T>
//class shared_ptr
//{
//public:
//	explicit shared_ptr(T* ptr = nullptr)
//		: _ptr(ptr)
//		, _pcount(new int(1))
//	{
//	}
//
//	template<class D>
//	shared_ptr(T* ptr, D del)
//		: _ptr(ptr)
//		, _pcount(new int(1))
//		, _del(del)
//	{
//	}
//
//	shared_ptr(const shared_ptr<T>& sp)
//		:_ptr(sp._ptr)
//		, _pcount(sp._pcount)
//		, _del(sp._del)
//	{
//		++(*_pcount);
//	}
//
//	void release()
//	{
//		if (--(*_pcount) == 0)
//		{
//			// 最后⼀个管理的对象，释放资源
//			_del(_ptr);
//			delete _pcount;
//			_ptr = nullptr;
//			_pcount = nullptr;
//		}
//	}
//
//	shared_ptr<T>& operator=(const shared_ptr<T>& sp)
//	{
//		if (_ptr != sp._ptr)
//		{
//			release();
//			_ptr = sp._ptr;
//			_pcount = sp._pcount;
//			++(*_pcount);
//			_del = sp._del;
//		}
//		return *this;
//	}
//
//	~shared_ptr()
//	{
//		release();
//	}
//
//	T* get() const
//	{
//		return _ptr;
//	}
//
//	int use_count() const
//	{
//		return *_pcount;
//	}
//
//	T& operator*()
//	{
//		return *_ptr;
//	}
//
//	T* operator->()
//	{
//		return _ptr;
//	}
//
//private:
//	T* _ptr;
//	int* _pcount;
//	//atomic<int>* _pcount;
//	function<void(T*)> _del = [](T* ptr) {delete ptr; };
//};
//
//// 需要注意的是我们这⾥实现的shared_ptr和weak_ptr都是以最简洁的⽅式实现的，
//// 只能满⾜基本的功能，这⾥的weak_ptr lock等功能是⽆法实现的，想要实现就要
//// 把shared_ptr和weak_ptr⼀起改了，把引⽤计数拿出来放到⼀个单独类型，shared_ptr
//// 和weak_ptr都要存储指向这个类的对象才能实现，有兴趣可以去翻翻源代码
//template<class T>
//class weak_ptr
//{
//public:
//	weak_ptr()
//	{
//	}
//	weak_ptr(const shared_ptr<T>& sp)
//		:_ptr(sp.get())
//	{
//	}
//	weak_ptr<T>& operator=(const shared_ptr<T>& sp)
//	{
//		_ptr = sp.get();
//		return *this;
//	}
//private:
//	T* _ptr = nullptr;
//};
//}

namespace wusaqi
{
	template <class T>
	class shared_ptr
	{
	public:
		//默认+带参构造
		shared_ptr(T* ptr = nullptr)
			:_ptr(ptr)
			, _pcount(new int(1))
		{
		}

		//
		template<class D>
		shared_ptr(T* ptr, D del)
			:_ptr(ptr)
			,_pcount(new int(1))
			,_del(del)
		{
		}

		//拷贝构造
		shared_ptr(const shared_ptr<T>& sp)
			:_ptr(sp._ptr)
			, _pcount(sp._pcount)
		{
			//拷贝构造后又有一份指针指向_ptr指向的资源
			//把计数器加一
			++(*_pcount);
		}

		//释放资源
		void release()
		{
			if (--(*_pcount) == 0)
			{
				//计数器为0则释放资源和计数器
				_del(_ptr);
				delete _pcount;
				_ptr = nullptr;
				_pcount = nullptr;
			}
		}

		//赋值运算符重载
		shared_ptr<T>& operator=(const shared_ptr<T>& sp)
		{
			//避免自赋值
			if (_ptr != sp._ptr)
			{
				release();

				_ptr = sp._ptr;
				_pcount = sp._pcount;
				++(*_pcount);
			}

			return *this;
		}

		//析构
		~shared_ptr()
		{
			release();
		}

		T* get() const
		{
			return _ptr;
		}

		int use_count() const
		{
			return *_pcount;
		}

		T& operator*()
		{
			return *_ptr;
		}

		T* operator->()
		{
			return _ptr;
		}

	private:
		T* _ptr;
		int* _pcount;
		function<void(T*)> _del;
	};
}

//函数模板
template<class T>
void DeleteArrayFunc(T* ptr)
{
	delete[] ptr;
}

//仿函数
template<class T>
class DeleteArray
{
public:
	void operator()(T* ptr)
	{
		delete[] ptr;
	}
};

class Fclose
{
public:
	void operator()(FILE* ptr)
	{
		cout << "fclose:" << ptr << endl;
		fclose(ptr);
	}
};


int main()
{
	// 这样实现程序会崩溃
	// unique_ptr<Date> up1(new Date[10]);
	// shared_ptr<Date> sp1(new Date[10]);
	// 解决⽅案1
	// 因为new[]经常使⽤，所以unique_ptr和shared_ptr
	// 实现了⼀个特化版本，这个特化版本析构时⽤的delete[]
	//unique_ptr<Date[]> up1(new Date[5]);
	//shared_ptr<Date[]> sp1(new Date[5]);

	// 解决⽅案2
	// 仿函数对象做删除器
	//unique_ptr<Date, DeleteArray<Date>> up2(new Date[5], DeleteArray<Date>());
	// unique_ptr和shared_ptr⽀持删除器的⽅式有所不同
	// unique_ptr是在类模板参数⽀持的，shared_ptr是构造函数参数⽀持的
	// 这⾥没有使⽤相同的⽅式还是挺坑的
	// 使⽤仿函数unique_ptr可以不在构造函数传递，因为仿函数类型定义的对象直接就可以调⽤
	// 但是下⾯的函数指针和lambda的类型不可以，除了在类模板传递，还需要在构造函数传递
	// 因为函数指针定义的对象是空指针，还需要把函数指针的值传递进来
	unique_ptr<Date, DeleteArray<Date>> up2(new Date[5]);
	wusaqi::shared_ptr<Date> sp2(new Date[5], DeleteArray<Date>());

	// 函数指针做删除器
	unique_ptr<Date, void(*)(Date*)> up3(new Date[5], DeleteArrayFunc<Date>);
	wusaqi::shared_ptr<Date> sp3(new Date[5], DeleteArrayFunc<Date>);

	// lambda表达式做删除器
	auto delArrOBJ = [](Date* ptr) {delete[] ptr; };
	unique_ptr<Date, decltype(delArrOBJ)> up4(new Date[5], delArrOBJ);
	wusaqi::shared_ptr<Date> sp4(new Date[5], delArrOBJ);

	// 实现其他资源管理的删除器
	wusaqi::shared_ptr<FILE> sp5(fopen("Test.cpp", "r"), Fclose());
	wusaqi::shared_ptr<FILE> sp6(fopen("Test.cpp", "r"), [](FILE* ptr) {
	cout << "fclose:" << ptr << endl;
	fclose(ptr);
	   });

	return 0;
}

//int main()
//{
//	shared_ptr<Date> sp1(new Date(2024, 9, 11));
//	shared_ptr<Date> sp2 = make_shared<Date>(2024, 9, 11);
//	auto sp3 = make_shared<Date>(2024, 9, 11);
//	shared_ptr<Date> sp4;
//	// if (sp1.operator bool())
//	if (sp1)
//		cout << "sp1 is not nullptr" << endl;
//	if (!sp4)
//		cout << "sp1 is nullptr" << endl;
//	// 报错
//	shared_ptr<Date> sp5 = new Date(2024, 9, 11);
//	unique_ptr<Date> sp6 = new Date(2024, 9, 11);
//	return 0;
//}

//int main()
//{
	//wusaqi::shared_ptr<Date> ptr1 = new Date;
	//wusaqi::shared_ptr<Date> ptr2 = ptr1;

	//wusaqi::shared_ptr<Date> ptr3 = new Date;

	//ptr1 = ptr1;
	//ptr2 = ptr2;

	//ptr1 = ptr3; 
	//ptr2 = ptr3;

//	wusaqi::shared_ptr<Date> ptr1 = new Date[10];
//	return 0;
//}

//int main()
//{
//	bit::auto_ptr<Date> ap1(new Date);
//	// 拷⻉时，管理权限转移，被拷⻉对象ap1悬空
//	bit::auto_ptr<Date> ap2(ap1);
//	// 空指针访问，ap1对象已经悬空
//	//ap1->_year++;
//	
//	bit::unique_ptr<Date> up1(new Date);
//	// 不⽀持拷⻉
//	//unique_ptr<Date> up2(up1);
//	// ⽀持移动，但是移动后up1也悬空，所以使⽤移动要谨慎
//	bit::unique_ptr<Date> up3(move(up1));
//
//	bit::shared_ptr<Date> sp1(new Date);
//	// ⽀持拷⻉
//	bit::shared_ptr<Date> sp2(sp1);
//	bit::shared_ptr<Date> sp3(sp2);
//	cout << sp1.use_count() << endl;
//	sp1->_year++;
//	cout << sp1->_year << endl;
//	cout << sp2->_year << endl;
//	cout << sp3->_year << endl;
//	return 0;
//}


